#include "jsonprocesshelper.h"

namespace DataSpecificationGW
{
    template <typename src_t, typename dst_t>
    bool __convert(const src_t& src, dst_t& dst)
    {
        if (src.IsBool())
        {
            dst.SetBool(src.GetBool());
        }
        else if (src.IsInt())
        {
            dst.SetInt(src.GetInt());
        }
        else if (src.IsUint())
        {
            dst.SetUint(src.GetUint());
        }
        else if (src.IsInt64())
        {
            dst.SetInt64(src.GetInt64());
        }
        else if (src.IsUint64())
        {
            dst.SetUint64(src.GetUint64());
        }
        else if (src.IsDouble())
        {
            dst.SetDouble(src.GetDouble());
        }
        else if (src.IsString())
        {
            dst.SetString(rapidjson::StringRef(src.GetString()));
        }
        else if (src.IsNull())
        {
            dst.SetNull();
        }
        else
        {
            return false;
        }
        return true;
    }

    bool saveJSONDocument(rapidjson::Value& dst, rapidjson::Document& src)
    {
        rapidjson::Document::AllocatorType& allocator = src.GetAllocator();
        if (dst.IsArray())
        {
            src.SetArray();
            rapidjson::SizeType size = dst.Size();
            for (rapidjson::SizeType i = 0; i < size; ++i)
            {
                src.PushBack(dst[i].Move(), allocator);
            }
            return true;
        }
        else if (dst.IsObject())
        {
            src.SetObject();
            for (rapidjson::Value::MemberIterator it = dst.MemberBegin(); it != dst.MemberEnd(); ++it)
            {
                src.AddMember(rapidjson::StringRef(it->name.GetString()), it->value.Move(), allocator);
            }
            return true;
        }
        return __convert(dst, src);
    }


    bool parseJSONDocument(rapidjson::Document& src, rapidjson::Value& dst)
    {
        rapidjson::Document::AllocatorType& allocator = src.GetAllocator();
        if (src.IsArray())
        {
            dst.SetArray();
            rapidjson::SizeType size = src.Size();
            for (rapidjson::SizeType i = 0; i < size; ++i)
            {
                dst.PushBack(src[i].Move(), allocator);
            }
            return true;
        }
        else if (src.IsObject())
        {
            dst.SetObject();
            for (rapidjson::Document::MemberIterator it = src.MemberBegin(); it != src.MemberEnd(); ++it)
            {
                dst.AddMember(rapidjson::StringRef(it->name.GetString()), it->value.Move(), allocator);
            }
            return true;
        }
        return __convert(src, dst);
    }

    //////////////////////////////////////////////////////////////////////////
    //

    // bool
    bool saveJSON(const bool& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetBool(objValue);
        return true;
    }

    bool parseJSON(const rapidjson::Value& jsonValue, bool& objValue)
    {
        if (jsonValue.IsBool())
        {
            objValue = jsonValue.GetBool();
            return true;
        }
        else if (jsonValue.IsInt())
        {
            int tmp = jsonValue.GetInt();
            if (!tmp)
            {
                objValue = false;
            }
            else
            {
                objValue = true;
            }
            return true;
        }
        return false;
    }
    // std::string
    bool saveJSON(const std::string& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetString(rapidjson::StringRef(objValue.c_str()));
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, std::string& objValue)
    {
        if (jsonValue.IsString())
        {
            objValue = jsonValue.GetString();
            return true;
        }
        return false;
    }

#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
    // int32_t
    bool saveJSON(const int32_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetInt(objValue);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, int32_t& objValue)
    {
        if (jsonValue.IsInt())
        {
            objValue = jsonValue.GetInt();
            return true;
        }
        return false;
    }
    // uint32_t
    bool saveJSON(const uint32_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetUint(objValue);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, uint32_t& objValue)
    {
        if (jsonValue.IsInt())
        {
            objValue = jsonValue.GetInt();
            return true;
        }
        else if (jsonValue.IsUint())
        {
            objValue = jsonValue.GetUint();
            return true;
        }
        return false;
    }
    // double
    bool saveJSON(const double& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetDouble(objValue);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, double & objValue)
    {
        if (jsonValue.IsNumber())
        {
            objValue = jsonValue.GetDouble();
            return true;
        }
        return false;
    }

    // int64_t & uint64_t
    bool saveJSON(const int64_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetInt64(objValue);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, int64_t& objValue)
    {
        if (jsonValue.IsInt64())
        {
            objValue = jsonValue.GetInt64();
            return true;
        }
        else if (jsonValue.IsInt())
        {
            objValue = jsonValue.GetInt();
            return true;
        }
        else if (jsonValue.IsUint())
        {
            objValue = jsonValue.GetUint();
            return true;
        }
        return false;
    }
    bool saveJSON(const uint64_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetUint64(objValue);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, uint64_t& objValue)
    {
        if (jsonValue.IsUint64())
        {
            objValue = jsonValue.GetUint64();
            return true;
        }
        else if (jsonValue.IsInt())
        {
            objValue = jsonValue.GetInt();
            return true;
        }
        else if (jsonValue.IsUint())
        {
            objValue = jsonValue.GetUint();
            return true;
        }
        return false;
    }



    //////////////////////////////////////////////////////////////////////////
    //

    // int8_t & uint8_t
    bool saveJSON(const int8_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        int32_t objValueTmp = static_cast<int32_t>(objValue);
        return saveJSON(objValueTmp, alloc, jsonValue);
    }
    bool parseJSON(const rapidjson::Value& jsonValue, int8_t& objValue)
    {
        int32_t objValueTmp = 0;
        if (!parseJSON(jsonValue, objValueTmp))
        {
            return false;
        }
        objValue = static_cast<int8_t>(objValueTmp);
        return true;
    }

    bool saveJSON(const uint8_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        uint32_t objValueTmp = static_cast<uint32_t>(objValue);
        return saveJSON(objValueTmp, alloc, jsonValue);
    }
    bool parseJSON(const rapidjson::Value& jsonValue, uint8_t& objValue)
    {
        uint32_t objValueTmp = 0;
        if (!parseJSON(jsonValue, objValueTmp))
        {
            return false;
        }
        objValue = static_cast<uint8_t>(objValueTmp);
        return true;
    }
    // int16_t & uint16_t
    bool saveJSON(const int16_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        int32_t objValueTmp = static_cast<int32_t>(objValue);
        return saveJSON(objValueTmp, alloc, jsonValue);
    }
    bool parseJSON(const rapidjson::Value& jsonValue, int16_t& objValue)
    {
        int32_t objValueTmp = 0;
        if (!parseJSON(jsonValue, objValueTmp))
        {
            return false;
        }
        objValue = static_cast<int16_t>(objValueTmp);
        return true;
    }

    bool saveJSON(const uint16_t& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        uint32_t objValueTmp = static_cast<uint32_t>(objValue);
        return saveJSON(objValueTmp, alloc, jsonValue);
    }
    bool parseJSON(const rapidjson::Value& jsonValue, uint16_t& objValue)
    {
        uint32_t objValueTmp = 0;
        if (!parseJSON(jsonValue, objValueTmp))
        {
            return false;
        }
        objValue = static_cast<uint16_t>(objValueTmp);
        return true;
    }

    // float
    bool saveJSON(const float& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        double objValueTmp = objValue;
        return saveJSON(objValueTmp, alloc, jsonValue);
    }
    bool parseJSON(const rapidjson::Value& jsonValue, float & objValue)
    {
        double objValueTmp = 0;
        if (!parseJSON(jsonValue, objValueTmp))
        {
            return false;
        }
        objValue = static_cast<float>(objValueTmp);
        return true;
    }
#endif


    //////////////////////////////////////////////////////////////////////////
    //

    // QString
    bool saveJSON(const QString& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetString(objValue.toUtf8().data(), alloc);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, QString& objValue)
    {
        if (jsonValue.IsString())
        {
            objValue = QString::fromUtf8(jsonValue.GetString());
            return true;
        }
        return false;
    }

    // QByteArray
    bool saveJSON(const QByteArray& objValue, allocator_t& alloc, rapidjson::Value& jsonValue)
    {
        jsonValue.SetString(objValue.toBase64(), alloc);
        return true;
    }
    bool parseJSON(const rapidjson::Value& jsonValue, QByteArray& objValue)
    {
        if (jsonValue.IsString())
        {
            objValue = QByteArray::fromBase64(jsonValue.GetString());
            return true;
        }
        return false;
    }
}
